package com.sneakxy.cloudbase.platform.handler;

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.web.ErrorProperties;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.DefaultErrorWebExceptionHandler;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.cloud.gateway.support.NotFoundException;
import org.springframework.cloud.gateway.support.ServiceUnavailableException;
import org.springframework.context.ApplicationContext;
import org.springframework.web.reactive.function.server.RequestPredicates;
import org.springframework.web.reactive.function.server.RouterFunction;
import org.springframework.web.reactive.function.server.RouterFunctions;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import org.springframework.web.server.ResponseStatusException;

import com.alibaba.csp.sentinel.cluster.exception.SentinelClusterException;
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;

import reactor.netty.http.client.PrematureCloseException;

public class GlobalExceptionHandler extends DefaultErrorWebExceptionHandler {

	protected final Logger log = LoggerFactory.getLogger(getClass());
	
	
	
	public GlobalExceptionHandler(ErrorAttributes errorAttributes, ErrorProperties errorProperties,
			ApplicationContext applicationContext) {
		super(errorAttributes, new WebProperties.Resources(), errorProperties, applicationContext);
	}

	@Override
	protected Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
		return getErrorAttributes(request);
	}

	/**
	 * 获取异常属性
	 */
	@Override
	protected Map<String, Object> getErrorAttributes(ServerRequest request, boolean includeStackTrace) {
		return getErrorAttributes(request);
	}

	protected Map<String, Object> getErrorAttributes(ServerRequest request) {
		Throwable error = super.getError(request);
		int code = 500;
		String message;
		if(error instanceof SentinelClusterException || error instanceof SentinelRpcException) {
			message = "服务调用熔断,请联系管理员.";
			log.error("服务调用熔断未实现", error);
		} else if(error instanceof ServiceUnavailableException || error instanceof NotFoundException) {
			message = "功能服务未启动,请联系管理员.";
			log.error("服务未开启", error);
		} else if(error.getClass().isAssignableFrom(PrematureCloseException.class)) {
			message = "上传文件过大.";
		} else if(error instanceof ResponseStatusException) {
			code = ((ResponseStatusException) error).getStatus().value();
			message = "发生未知错误,请联系管理员.";
		} else {
			log.error("未知异常", error);
			message = "发生未知错误,请联系管理员.";
		}
		return response(code, message);
	}
	
	/**
	 * 指定响应处理方法为JSON处理的方法
	 * @param errorAttributes
	 */
	@Override
	protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
		return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
	}

	/**
	 * 根据code获取对应的HttpStatus
	 * @param errorAttributes
	 */
	@Override
	protected int getHttpStatus(Map<String, Object> errorAttributes) {
		return (int) errorAttributes.get("code");
	}

	/**
	 * 构建返回的JSON数据格式
	 * @param status		状态码
	 * @param errorMessage  异常信息
	 * @return
	 */
	public static Map<String, Object> response(int status, String errorMessage) {
		Map<String, Object> map = new HashMap<>();
		map.put("success", false);
		map.put("code", status);
		map.put("message", errorMessage);
		map.put("data", null);
		return map;
	}
	
}
